import knex from '../db/sql'
import {Context, MetheodType, Next} from 'TYPE';
import {parameter, validateBody, validateQuery} from '../parameter_m';
import {userDB} from '../db/sqltable/user.db';
import {User} from 'knex/types/tables';
import {passwordCompare, passwordEncrypt} from '../EDHR';
import {emailTo} from '../sendEmail';
import {userRelativeDB} from '../db/sqltable/user_relative.db';
import {userPostRelationDB} from '../db/sqltable/user_post_relation.db';

export default class UserController {
    static checkLogin(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        const original = descriptor.value
        descriptor.value = async (ctx: Context, next: Next) => {
            await UserController.hasLogin(ctx, null).then(() => {
                if (ctx.cd !== 0) {
                    next()
                } else {
                    return original(ctx, next)
                }
            })
        }
    }

    @UserController.checkLogin
    @validateBody({
        newUsername: 'string',
    })
    static async changeUsername(ctx: Context, next: Next) {
        let {newUsername} = ctx.validatedParams
        if (newUsername == ctx.user.user_name) {
            ctx.cd = 1
            ctx.msg = "用户名重复！！"
        }
        else if (await userDB.nameExists(newUsername)) {
            ctx.cd = 1
            ctx.msg = "用户名已存在！！"
        } else {
            await knex('users').where({uid: ctx.user.uid}).update({
                user_name: newUsername
            }).then((num) => {
                if (num > 0) {
                    ctx.session.user.user_name = newUsername
                }
            })
            ctx.cd = 0
            ctx.msg = "修改成功"
            userDB.updateCache(ctx.user.uid)
        }

        next()
    }

    @UserController.checkLogin
    @validateBody({
        password: 'string',
        newpassword: 'string'
    })
    static async changePassword(ctx: Context, next: Next) {
        let {password, newpassword} = ctx.validatedParams
        if (passwordCompare(password, ctx.user.pwd)) {
            if (password === newpassword) {
                ctx.cd = 1
                ctx.msg = "密码重复！！"
            }
            else {
                const newpwd = passwordEncrypt(newpassword)
                await knex('users').where({uid: ctx.user.uid}).update({
                    pwd: newpwd
                }).then((num) => {
                    if (num > 0) {
                        ctx.session.user.pwd = newpwd
                    }
                })
                ctx.cd = 0
                ctx.msg = "修改成功"
                userDB.updateCache(ctx.user.uid)
            }
        } else {
            ctx.cd = 1
            ctx.msg = "密码错误！！"
        }

        next()
    }
    @validateBody({
        username: 'string',
        password: {type: 'password', required: true, allowEmpty: false, min: 6, max: 32}
    })
    static async login(ctx: Context, next: Next) {
        let {username, password} = ctx.validatedParams
        let user = await userDB.nameExists(username) as any || await userDB.emailExists(username)
        if (ctx.session.loginLockTime) {
            let interval = (new Date().getTime() - ctx.session.loginLockTime) / 1000.0
            if (interval > 60) {
                delete ctx.session.loginLockTime
                ctx.session.pwdInputTime = 0
            } else {
                ctx.cd = 1
                ctx.msg = `失败次数过多，请${(60 - interval) >> 0}秒后再登录。`
                await next()
                return
            }
        }
        if (user && passwordCompare(password, user.pwd)) {
            ctx.session.user = user
            ctx.session.pwdInputTime = 0
            ctx.cd = 0
            ctx.msg = "登录成功"
            user = JSON.parse(JSON.stringify(user))
            delete user.pwd
            ctx.return = user
        }
        else {
            ctx.session.user = undefined
            ctx.session.pwdInputTime = ctx.session.pwdInputTime || 0
            ctx.session.pwdInputTime++
            if (ctx.session.pwdInputTime >= 10) {
                ctx.session.loginLockTime = ctx.session.loginLockTime || new Date().getTime()
            }
            ctx.cd = 1
            ctx.msg = "用户名或密码错误！！" + "尝试次数 " + ctx.session.pwdInputTime
        }
        next()
    }
    static async hasLogin(ctx: Context, next: Next) {
        next = next || (() => {}) as any
        if (ctx.session.user) {
            ctx.cd = 0
            ctx.msg = "已登录"
            ctx.user = ctx.session.user
            ctx.return = JSON.parse(JSON.stringify(ctx.session.user))
            ctx.return.pwd = undefined
        } else {
            ctx.cd = 1
            ctx.msg = "未登录"
        }
        next()
    }
    @UserController.checkLogin
    static async changeAvatar(ctx: Context, next: Next) {
        let image_path = null
        if (ctx.request.files && ctx.request.files.image) {
            image_path = (ctx.request.files.image as any).newFilename as string
        }
        if (!image_path) {
            ctx.cd = 1
            ctx.msg = "文件错误！！"
            next()
            return
        }
        await knex('users').where({uid: ctx.user.uid}).update({avatar: image_path}).then(num => {
            if (num > 0) {
                ctx.cd = 0
                ctx.msg = "更新头像成功"
                ctx.user.avatar = image_path
                userDB.updateCache(ctx.user.uid)
            } else {
                ctx.cd = 1
                ctx.msg = "更新头像失败！！"
            }
        })

        next()
    }

    @UserController.checkLogin
    static async logout(ctx: Context, next: Next) {
        if (ctx.cd === 0) {
            ctx.session.user = undefined
            ctx.msg = "登出成功"
        }
        next()
    }

    @UserController.checkLogin
    @validateBody({
        name: {type: 'string', required: false, allowEmpty: false, min: 2, max: 10},
        hide_name: 'number?',
        tel: {type: 'string', required: false, allowEmpty: false, min: 8, max: 13},
        hide_tel: 'number?',
        college_class: {type: 'string', required: false, allowEmpty: false, min: 3, max: 10},
        hide_class: 'number?',
        hide_email: 'number?',
        signature: {type: 'string', required: false, allowEmpty: false, min: 1, max: 150},
        gender: {type: 'string', required: false, allowEmpty: false, min: 1, max: 2},
    })
    static async setData(ctx: Context, next: Next) {
        let {name, tel, hide_name, hide_tel, college_class, hide_class,hide_email, gender, signature, } = ctx.validatedParams
        console.log(ctx.validatedParams);
        
        let user = ctx.user
        if (name) user.name = name
        if (tel) user.tel = tel
        if (gender) user.gender = gender
        if (college_class) user.college_class = college_class
        if (signature) user.signature = signature
        if (hide_name != undefined) user.hide_name = !!hide_name
        if (hide_class != undefined) user.hide_class = !!hide_class
        if (hide_tel != undefined) user.hide_tel = !!hide_tel
        if (hide_email != undefined) user.hide_email = !!hide_email

        await knex('users').update(user).where({uid: user.uid}).then(num => {
            if (num > 0) {
                ctx.cd = 0
                ctx.msg = "更新用户数据成功"
                ctx.session.user = {...ctx.session.user, ...user}
                userDB.updateCache(ctx.user.uid)
                ctx.return = JSON.parse(JSON.stringify(user))
                ctx.return.pwd = undefined
            } else {
                ctx.cd = 1
                ctx.msg = "更新用户数据失败！！"
            }
        })
        next()
    }

    @validateQuery({username: 'string?', email: 'email?'})
    static async userExists(ctx: Context, next: Next) {
        next = next || (() => {}) as any
        let {username, email} = ctx.validatedParams
        let user = null
        if (username)
            user = await userDB.nameExists(username)
        else if (email)
            user = await userDB.emailExists(email)

        if (user) {
            ctx.cd = 0
            ctx.msg = "用户存在"

            ctx.user = JSON.parse(JSON.stringify(user))
            ctx.return = user
            ctx.return.pwd = undefined
        } else {
            ctx.cd = 1
            ctx.msg = "用户不存在"
        }

        next()
    }
    static vcLength = 6
    // 发送邮箱验证码
    @validateQuery({
        email: 'email',
    })
    static async sendEmailVC(ctx: Context, next: Next) {
        let {email} = ctx.validatedParams
        if (ctx.session.registry) {
            const interval = new Date().getTime() - ctx.session.registry.time
            if (interval / 1000.0 < 10) {
                ctx.cd = 1
                ctx.msg = "请求次数过多"
                await next()
                return
            }
        }
        let user = await userDB.emailExists(email)
        if (user) {
            ctx.cd = 1
            ctx.msg = "邮箱已被注册"
            await next()
            return
        }
        let vc = ""
        let i = UserController.vcLength
        while (i--) vc += Math.floor(Math.random() * 10)

        ctx.session.registry = {email, vc, time: new Date().getTime(), checked: false}
        console.log(vc);
        emailTo(email, "【cauis】邮箱验证", `您的验证码是${vc},请尽快使用。`, 'text').then(info => {
            console.log(info);
        }).catch(console.error)

        ctx.cd = 0
        ctx.msg = "验证码已发送"
        next()
    }
    // 验证邮箱验证码
    @validateQuery({
        vc: {
            required: true, allowEmpty: false,
            min: UserController.vcLength,
            max: UserController.vcLength, type: 'string'
        },
    })
    static async checkEmailVC(ctx: Context, next: Next) {
        let {vc} = ctx.validatedParams
        if (ctx.session.registry) {
            const interval = new Date().getTime() - ctx.session.registry.time
            if (interval / 1000.0 >= 10 * 60) {
                ctx.cd = 1
                ctx.msg = "验证码已过期"
                await next()
                return
            }
            if (vc == ctx.session.registry.vc) {
                ctx.cd = 0
                ctx.msg = "验证成功"
                ctx.session.registry.checked = true
            } else {
                ctx.cd = 1
                ctx.msg = "错误的验证码"
                await next()
                return
            }
        } else {// 没有注册信息
            ctx.cd = 1
            ctx.msg = "错误"
            await next()
            return
        }
        next()
    }

    // 创建用户
    @validateBody({
        username: 'string',
        email: 'email',
        password: {type: 'password', required: true, allowEmpty: false, min: 6, max: 32}
    })
    static async registry(ctx: Context, next: Next) {
        let {username, password, email} = ctx.validatedParams

        let user = await userDB.nameExists(username)
        if (user) {
            ctx.cd = 1
            ctx.msg = "用户名已存在！"
            await next()
            return
        }
        if (!ctx.session.registry || !ctx.session.registry.checked) {
            ctx.cd = 1
            ctx.msg = "邮箱未验证！"
            await next()
            return
        } else if (email != ctx.session.registry.email) {
            ctx.cd = 1
            ctx.msg = "邮箱错误！"
            await next()
            return
        }
        await knex('users')
            .insert([{user_name: username, email, pwd: passwordEncrypt(password)}])
            .then((id) => {
                if (id.length > 0) {
                    ctx.cd = 0
                    ctx.msg = "注册成功！"
                    userDB.updateCache(id[0])
                    userPostRelationDB.initAchievement(id[0])
                }
                else {
                    ctx.cd = 1
                    ctx.msg = "注册失败！"
                }
            })
        next()
        // if(user){
        //     return {

        //     }
        // }
    }
    @validateQuery({userId: 'number', details: 'number'})
    static async getUserData(ctx: Context, next: Next) {
        let {userId, details} = ctx.validatedParams

        if (!userId) return null
        let user: User = await userDB.getUserById(userId,false,!!details)
        if (!user) {
            ctx.cd = 1
            ctx.msg = "无此用户！！"
            await next()
            return
        }
        
        ctx.cd = 0
        ctx.msg = "查找成功"
        ctx.return = user
        await next()
    }
    @validateQuery({user_name: 'string'})
    static async getUsersByUserName(ctx: Context, next: Next) {
        let users: any[]
        let {user_name} = ctx.validatedParams
        console.log(user_name);

        // let col = ['uid', 'user_name', 'name', 'avatar']
        // if (user_name) {
        //     user_name = `%${user_name}%`
        //     users = await knex('users').select(col).where('user_name', 'like', user_name)
        // } else {
        //     users = await knex('users').select(col)
        // }
        // console.log(users);

        ctx.cd = 0
        ctx.msg = "搜索用户成功"
        ctx.return = users

        next()
    }

    @UserController.checkLogin
    @validateQuery({
        uid: 'number',
        relationship: userRelativeDB.relationships,
        value: 'string'
    })
    static async changeUserRelative(ctx: Context, next: Next) {
        let {uid, relationship, value} = ctx.validatedParams

        const user = ctx.user
        value = !!value && value !== 'false';

        if (userDB.getUserById(uid)) {
            if (value)
                await userRelativeDB.addRelative(user.uid, uid, relationship)
            else
                await userRelativeDB.removeRelative(user.uid, uid, relationship)
            ctx.cd = 0
            ctx.msg = "操作成功"
        } else {
            ctx.cd = 1
            ctx.msg = "无此用户"
            await next()
            return
        }
        await next()
    }
}
